#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <unistd.h>

#define BOARD_WIDTH 10
#define BOARD_HEIGHT 20
#define TOTAL_BLOCK_TYPES 7

typedef struct {
    int deltaY;
    int deltaX;
} ShapeBlock;

ShapeBlock blockShapes[TOTAL_BLOCK_TYPES][4][4] = {
    // I型
    {
        {{0,0}, {0,1}, {0,2}, {0,3}},
        {{0,0}, {1,0}, {2,0}, {3,0}},
        {{0,0}, {0,1}, {0,2}, {0,3}},
        {{0,0}, {1,0}, {2,0}, {3,0}},
    },
    // O型
    {
        {{0,0}, {1,0}, {0,1}, {1,1}},
        {{0,0}, {1,0}, {0,1}, {1,1}},
        {{0,0}, {1,0}, {0,1}, {1,1}},
        {{0,0}, {1,0}, {0,1}, {1,1}}
    },
    // T型
    {
        {{1,0}, {0,1}, {1,1}, {1,2}},
        {{0,0}, {1,0}, {2,0}, {1,1}},
        {{1,0}, {0,1}, {1,1}, {1,2}},
        {{0,1}, {1,1}, {2,1}, {1,0}},
    },
    // Z型
    {
        {{0,0}, {0,1}, {1,1}, {1,2}},
        {{1,0}, {2,0}, {0,1}, {1,1}},
        {{0,0}, {0,1}, {1,1}, {1,2}},
        {{1,0}, {2,0}, {0,1}, {1,1}},
    },
    // S型
    {
        {{1,0}, {0,1}, {1,1}, {0,2}},
        {{0,0}, {1,0}, {1,1}, {2,1}},
        {{1,0}, {0,1}, {1,1}, {0,2}},
        {{0,0}, {1,0}, {1,1}, {2,1}},
    },
    // J型
    {
        {{1,0}, {1,1}, {1,2}, {0,0}},
        {{0,0}, {0,1}, {1,0}, {2,0}},
        {{0,0}, {0,1}, {0,2}, {1,2}},
        {{0,1}, {1,1}, {2,1}, {2,0}},
    },
    // L型
    {
        {{1,0}, {1,1}, {1,2}, {0,2}},
        {{0,0}, {1,0}, {2,0}, {2,1}},
        {{0,0}, {1,0}, {0,1}, {0,2}},
        {{0,0}, {0,1}, {1,1}, {2,1}}
    }
};

const double scoringWeights[] = {
    -4.5,
    3.4,
    -3.1,
    -9.3,
    -7.8,
    -3.5
};

long int totalScore = 0;
int gameBoard[BOARD_HEIGHT][BOARD_WIDTH] = {0};
int tempBoard[BOARD_HEIGHT][BOARD_WIDTH] = {0};

int findLowestYPosition(int x, int rotation, int type) {
    ShapeBlock* shape = blockShapes[type][rotation];
    int maxY = -1;
    for (int y = 0; y <= BOARD_HEIGHT - 6; y++) {
        int isValid = 1;
        for (int i = 0; i < 4; i++) {
            int bx = x + shape[i].deltaX;
            int by = y + shape[i].deltaY;
            if (bx < 0 || bx >= BOARD_WIDTH || by < 0 || by >= BOARD_HEIGHT - 5 || gameBoard[by][bx]) {
                isValid = 0;
                break;
            }
        }
        if (isValid) maxY = y;
        else break;
    }
    return maxY;
}

int clearCompletedRows(int grid[BOARD_HEIGHT][BOARD_WIDTH]) {
    int totalCleared = 0; // 记录已消除的行数

    // 从底部向上逐行检查
    for (int currentRow = BOARD_HEIGHT - 6; currentRow >= 0; ) {
        // 计算当前行的填充单元数
        int filledCount = 0;
        for (int column = 0; column < BOARD_WIDTH; column++) {
            if (grid[currentRow][column]) {
                filledCount++;
            }
        }

        if (filledCount == BOARD_WIDTH) {
            // 当前行已满，增加已消除行数计数
            totalCleared++;

            // 将上方所有行下移
            for (int shiftRow = currentRow; shiftRow > 0; shiftRow--) {
                for (int column = 0; column < BOARD_WIDTH; column++) {
                    grid[shiftRow][column] = grid[shiftRow - 1][column];
                }
            }

            // 清空最上面一行
            for (int column = 0; column < BOARD_WIDTH; column++) {
                grid[0][column] = 0;
            }
        } else {
            // 当前行未满，继续向上检查
            currentRow--;
        }
    }

    return totalCleared; // 返回已消除的行数
}

int calculateScore(int lines) {
    const int points[] = {0, 100, 300, 500, 800};
    totalScore += points[lines];
    return points[lines];
}

void placeShape(int x, int y, int rotation, int type, int board[BOARD_HEIGHT][BOARD_WIDTH]) {
    ShapeBlock* shape = blockShapes[type][rotation];
    for (int i = 0; i < 4; i++) {
        int bx = x + shape[i].deltaX;
        int by = y + shape[i].deltaY;
        if (by >= 0 && by < BOARD_HEIGHT - 5 && bx >= 0 && bx < BOARD_WIDTH)
            board[by][bx] = 1;
    }
}

int calculateWellDepths(int board[BOARD_HEIGHT][BOARD_WIDTH]) {
    int wellDepthSum = 0;
    for (int x = 0; x < BOARD_WIDTH; x++) {
        for (int y = BOARD_HEIGHT - 6; y >= 0; y--) {
            if (!board[y][x]) {
                int left = (x == 0) ? 1 : board[y][x - 1];
                int right = (x == BOARD_WIDTH - 1) ? 1 : board[y][x + 1];
                if (left && right) {
                    int depth = 0;
                    for (int yy = y; yy >= 0; yy--) {
                        if (!board[yy][x] && (x == 0 || board[yy][x - 1]) && (x == BOARD_WIDTH - 1 || board[yy][x + 1])) {
                            depth++;
                        } else break;
                    }
                    for (int i = depth; i > 0; i--)
                        wellDepthSum += i;
                    y -= depth - 1;
                }
            }
        }
    }
    return wellDepthSum;
}

int calculateLandingHeight(int y, ShapeBlock* shape) {
    int maxY = 0;
    for (int i = 0; i < 4; i++) {
        int currentY = y + shape[i].deltaY;
        if (currentY > maxY) maxY = currentY;
    }
    return maxY;
}

void findOptimalMove(int type, int *optimalRotation, int *optimalX) {
    double bestScore = -INFINITY;
    *optimalRotation = 0;
    *optimalX = 0;

    for (int rot = 0; rot < 4; rot++) {
        ShapeBlock* shape = blockShapes[type][rot];
        int minX = 0, maxX = 0;
        for (int i = 0; i < 4; i++) {
            if (shape[i].deltaX < minX) minX = shape[i].deltaX;
            if (shape[i].deltaX > maxX) maxX = shape[i].deltaX;
        }

        int startX = -minX;
        int endX = BOARD_WIDTH - maxX - 1;

        for (int x = startX; x <= endX; x++) {
            int y = findLowestYPosition(x, rot, type);
            if (y == -1) continue;

            memcpy(tempBoard, gameBoard, sizeof(gameBoard));
            placeShape(x, y, rot, type, tempBoard);
            int lines = clearCompletedRows(tempBoard);

            double landingHeight = BOARD_HEIGHT - 5 - (y + calculateLandingHeight(y, shape)) / 2.0;
            int roughness = 0, columns = 0, holes = 0, wells = 0;

            // Calculate Roughness and Columns
            for (int yy = 0; yy < BOARD_HEIGHT - 5; yy++) {
                int prev = 1;
                for (int xx = 0; xx < BOARD_WIDTH; xx++) {
                    if (tempBoard[yy][xx] != prev) roughness++;
                    prev = tempBoard[yy][xx];
                }
                if (prev != 1) roughness++;
            }

            for (int xx = 0; xx < BOARD_WIDTH; xx++) {
                int prev = 1;
                for (int yy = 0; yy < BOARD_HEIGHT - 5; yy++) {
                    if (tempBoard[yy][xx] != prev) columns++;
                    prev = tempBoard[yy][xx];
                }
                if (prev != 1) columns++;
            }

            // Calculate Holes
            for (int xx = 0; xx < BOARD_WIDTH; xx++) {
                int blockAbove = 0;
                for (int yy = 0; yy < BOARD_HEIGHT - 5; yy++) {
                    if (tempBoard[yy][xx]) blockAbove = 1;
                    else if (blockAbove) holes++;
                }
            }

            // Calculate Wells
            wells = calculateWellDepths(tempBoard);

            double currentScore = 
                scoringWeights[0] * landingHeight +
                scoringWeights[1] * lines +
                scoringWeights[2] * roughness +
                scoringWeights[3] * columns +
                scoringWeights[4] * holes +
                scoringWeights[5] * wells;

            if (currentScore > bestScore) {
                bestScore = currentScore;
                *optimalRotation = rot;
                *optimalX = x;
            }
        }
    }
}

int getBlockTypeFromChar(char block) {
    switch (block) {
        case 'I': return 0;
        case 'O': return 1;
        case 'T': return 2;
        case 'Z': return 3;
        case 'S': return 4;
        case 'J': return 5;
        case 'L': return 6;
        default: return -1;
    }
}

void readFirstTwoChars(char* firstChar, char* secondChar) {
    while (scanf("%c%c", firstChar, secondChar) != 2) continue;
}

void readInputChar(char* inputChar) {
    scanf("%c", inputChar);
}

void outputResult(int x, int rotation) {
    printf("%d %d\n", rotation, x % 10);
    printf("%ld\n", totalScore);
    fflush(stdout);
}

int main() {
    int gameOver = 0;
    int blockType = 0, rotation = 0, x = 0;
    char firstChar = 0, secondChar = 0;
    totalScore = 0;
    memset(gameBoard, 0, sizeof(gameBoard));
    memset(tempBoard, 0, sizeof(tempBoard));

    readFirstTwoChars(&firstChar, &secondChar);
    while (!gameOver) {
        blockType = getBlockTypeFromChar(firstChar);
        if (blockType == -1) return 0;

        findOptimalMove(blockType, &rotation, &x);
        int y = findLowestYPosition(x, rotation, blockType);

        placeShape(x, y, rotation, blockType, gameBoard);
        int lines = clearCompletedRows(gameBoard);
        calculateScore(lines);

        outputResult(x, rotation);
        firstChar = secondChar;
        if (firstChar == 'X') return 0;
        getchar();
        readInputChar(&secondChar);
        if (secondChar == 'E') return 0;
    }
    return 0;
}